<template>
  <div>
    <div
      v-if="!isStudent"
      class="handleBtnCont">
      <el-button
        size="mini"
        v-if="this.jobId == null"
        type="success"
        style="margin-right: 50px"
        @click="showZLUpload"
        >知识点抽取</el-button
      >
      <el-button
        v-if="this.jobId == null"
        size="mini"
        type="primary"
        @click="createDir"
        >添加知识点</el-button
      >
      <el-button
        size="mini"
        v-if="this.jobId == null"
        type="warning"
        @click="checkGraph"
        >查看课程知识图谱</el-button
      >
      <!-- <el-button size="mini" type="danger" @click="batchDialog">批量设置</el-button> -->
    </div>

    <!--      :expand-row-keys="computedExpand"-->
    <el-tree
      v-if="this.jobId == null"
      draggable
      :data="treeData"
      :props="defaultProps"
      node-key="id"
      default-expand-all
      class="knowledge-tree">
      <template #default="{ node, data }">
        <div :class="['tree-node', data.type]">
          <!-- 节点内容 -->
          <div>{{ node.label }}</div>
          <div
            v-if="data.content"
            class="content-text">
            <el-tooltip
              class="item"
              effect="light"
              placement="top-start">
              <div
                slot="content"
                style="max-width: 70vw">
                {{ data.content }}
              </div>
              <div class="content-text">- {{ data.content }}</div>
            </el-tooltip>
          </div>
          <div></div>
          <div
            v-if="data.prerequisites"
            class="prerequisites"></div>

          <!-- 动态按钮 -->
          <span class="action-buttons">
            <!-- Chapter 节点：添加 SubChapter 按钮 -->
            <template v-if="data.type === 'chapter' && !isStudent">
              <el-tooltip
                content="添加子章节"
                placement="top">
                <el-button
                  icon="el-icon-plus"
                  type="text"
                  @click.stop="addSubChapter(node, data)">
                  <!--                <el-icon><Plus /></el-icon>-->
                </el-button>
              </el-tooltip>
            </template>

            <!-- SubChapter 节点：添加 Point 和删除按钮 -->
            <template v-if="data.type === 'sub_chapter' && !isStudent">
              <el-tooltip
                content="添加知识点"
                placement="top">
                <el-button
                  icon="el-icon-plus"
                  type="text"
                  size="mini"
                  @click.stop="addPoint(node, data)">
                </el-button>
              </el-tooltip>
              <el-tooltip
                content="删除子章节"
                placement="top">
                <el-button
                  type="text"
                  icon="el-icon-close"
                  @click.stop="deleteSubChapter(node, data)">
                </el-button>
              </el-tooltip>
            </template>

            <!-- Point 节点：修改和删除按钮 -->
            <template v-if="data.type === 'point' && !isStudent">
              <el-tooltip
                content="修改知识点"
                placement="top">
                <el-button
                  icon="el-icon-edit-outline"
                  type="text"
                  @click.stop="editPoint(data)">
                </el-button>
              </el-tooltip>
              <el-tooltip
                content="删除知识点"
                placement="top">
                <el-button
                  icon="el-icon-close"
                  type="text"
                  size="medium"
                  @click.stop="deletePoint(node, data)">
                </el-button>
              </el-tooltip>
            </template>
          </span>
        </div>
      </template>
    </el-tree>
    <div
      v-else
      class="waiting-container">
      <div class="waiting-content">
        <div class="waiting-header">
          <i class="el-icon-loading"></i>
          <h2>知识点抽取队列中</h2>
        </div>
        <div class="waiting-position">
          <div class="progress-wrapper">
            <div class="position-info">
              <span class="position-number">{{ positionBeforeYou }}</span>
              <span class="position-text">位用户在您前面</span>
            </div>
          </div>
          <div style="display: flex; width: 100%; justify-content: center; align-items: center">
            <img
              src="@/assets/waitting.png"
              style="width: 40%; padding: 24px" />
          </div>

          <p class="waiting-time">预计等待时间: {{ estimatedTime }}</p>
        </div>
        <div class="waiting-tips">
          <h3>等待小贴士</h3>
          <div class="tip-content">
            <p>{{ currentTip }}</p>
            <div class="tip-controls">
              <span
                @click="prevTip"
                class="tip-nav"
                ><i class="el-icon-arrow-left"></i
              ></span>
              <span class="tip-indicator">{{ tipIndex + 1 }}/{{ tips.length }}</span>
              <span
                @click="nextTip"
                class="tip-nav"
                ><i class="el-icon-arrow-right"></i
              ></span>
            </div>
          </div>
        </div>

        <div class="waiting-footer">
          <el-button
            size="large"
            type="primary"
            @click="checkQueuePosition"
            >刷新队列状态</el-button
          >
        </div>
      </div>
    </div>
    <course-file-dialog
      ref="childComponent"
      :visible.sync="dialogVisible"
      :excludes="excludes"
      @select="dialogSelect" />

    <el-dialog
      :visible.sync="batchVisible"
      :close-on-click-modal="false"
      title="批量赋值"
      width="500px">
      <div style="font-size: 12px; color: #ff3333; margin-bottom: 20px">
        *复选以批量改变值，不勾选维持现有数据
      </div>

      <el-form :model="batchForm">
        <el-form-item label="要求时长">
          <div style="display: flex; align-items: center">
            <el-checkbox
              v-model="batchForm.needLearnCk"
              style="margin-right: 20px" />
            <second-set v-model="batchForm.needLearn" />
          </div>
        </el-form-item>

        <el-form-item label="学完积分">
          <el-checkbox
            v-model="batchForm.pointsCk"
            style="margin-right: 20px" />
          <el-input-number
            v-model="batchForm.points"
            size="mini" />
        </el-form-item>
      </el-form>

      <div
        slot="footer"
        class="dialog-footer">
        <el-button
          type="primary"
          @click="confirmBatch()"
          >确 定</el-button
        >
      </div>
    </el-dialog>

    <el-dialog
      :visible.sync="catDialog"
      :close-on-press-escape="false"
      :close-on-click-modal="false"
      width="500px">
      <el-form
        v-model="importForm"
        label-position="left"
        label-width="80px">
        <el-form-item label="导入类目">
          <dic-catalog-tree
            v-model="importForm.catId"
            dic-code="course_file_catalog" />
        </el-form-item>

        <el-form-item label="导入方式">
          <el-radio
            v-model="importForm.type"
            :label="1"
            >下级目录及课件</el-radio
          >
          <el-radio
            v-model="importForm.type"
            :label="2"
            >本目录及其课件</el-radio
          >
        </el-form-item>
      </el-form>

      <div slot="footer">
        <el-button
          type="primary"
          @click="handleImport"
          >确认导入</el-button
        >
      </div>
    </el-dialog>

    <el-dialog
      :close-on-click-modal="false"
      :visible.sync="previewVisible"
      title="文件预览"
      width="60%"
      @close="closePreview">
      <el-alert
        v-if="previewData.fileType === '33'"
        title="内容由ai数字人生成，请注意甄别内容"
        type="info">
      </el-alert>
      <div style="overflow-x: hidden; overflow-y: auto">
        <div v-if="previewData.fileType === '33'">
          <video-player
            v-model="previewData.viewUrl"
            :ref-id="previewData.id"
            @loadError="vieoLoadError" />
        </div>
        <pdf-reader
          v-if="previewData.fileType === '11'"
          :src="previewData.viewUrl" />
        <pdf-reader
          v-if="previewData.fileType === '22'"
          :src="previewData.fileUrl" />
      </div>
    </el-dialog>
    <el-dialog
      :visible.sync="extrVisible"
      :close-on-click-modal="false"
      :before-close="closeExtr"
      title="知识点图谱"
      width="80%"
      style="min-width: 800px">
      <template #title>
        <div style="display: flex; justify-content: space-between">
          <div>{{ showGraphComponent ? "知识图谱" : "知识点抽取" }}</div>
        </div>
      </template>

      <div class="document-ipt-wrapper">
        <div v-show="!docLoading && !showGraphComponent">
          <div class="left">
            <el-alert
              :closable="false"
              title="* 试用期间仅生成10页内容的知识点, 请上传word/pdf课程教材，且不超过 100MB"
              type="warning" />
            <el-upload
              v-loading="docExtrLoading"
              class="upload"
              ref="docUpload"
              drag
              :data="uploadParams"
              :action="`${extractURI}/upload`"
              :limit="1"
              :on-exceed="handleDocExceed"
              :on-success="handleDocSuccess"
              :on-error="handleDocError"
              :on-change="handleDocFileChange"
              :on-remove="handleDocRemove"
              :before-upload="handleDocBeforeUpload"
              accept=".pdf,.doc,.docx">
              <div class="el-upload-area">
                <div
                  class="loading"
                  v-show="docBtnLoading">
                  <img src="@/assets/loading2.gif" />
                  <span>文件正在上传</span>
                </div>
                <i
                  class="el-icon-upload"
                  style="margin-top: 40px"></i>
                <div
                  class="el-upload__text"
                  style="text-align: center; font-size: 16px; font-weight: bold">
                  将文件拖拽到此处，或 <em>点击上传</em>
                </div>
              </div>
            </el-upload>
            <div class="buttons-container">
              <el-button
                style="width: 100%"
                size="large"
                type="primary"
                class="documentIpt_btn"
                @click.stop="submittextStructure"
                :disabled="docExtrLoading"
                >知识点生成</el-button
              >
            </div>
          </div>
        </div>

        <!-- 知识图谱组件 -->
        <div
          v-if="showGraphComponent"
          style="
            width: 100%;
            height: 100%;
            display: flex;
            align-items: center;
            flex-direction: column;
          ">
          <div
            ref="chart_container"
            class="content_container"
            v-loading="graphLoading"
            @dblclick="fullScreen">
            <div
              ref="chartContainer"
              class="tree-chart"
              style="width: 100%; height: 100%; overflow: hidden"></div>
          </div>
          <div class="buttons-container">
            <el-button
              size="large"
              type="primary"
              class="documentIpt_btn left_btn"
              @click="downloadImage"
              >下载图谱</el-button
            >
            <el-button
              size="large"
              type="primary"
              class="documentIpt_btn right_btn"
              @click="regenerateGraph"
              >重新生成</el-button
            >
          </div>
        </div>
        <div v-show="docLoading">
          <div class="loadingleft">
            <img
              src="@/assets/rerun.gif"
              alt="Loading Image"
              style="width: 300px; height: 200px; margin-top: 190px; margin-left: 130px" />
            <div class="progress-container">
              <div
                class="progress-bar"
                :style="{ width: docProgress + '%' }">
                <span style="margin-left: 420px; color: white">{{ docProgress }}%</span>
              </div>
              <p class="progress-text">{{ docProgressText }}</p>
            </div>
          </div>
          <div class="loadingright">
            <div
              class="image-text-container"
              style="margin-top: 80px; width: 800px; padding-left: 50px">
              <h1 style="font-size: 32px; text-align: center">课程知识点</h1>
              <p style="font-size: 26px; padding: 50px 100px 30px 50px">
                &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{{ docCurrentText }}
              </p>
              <img
                :src="loadingImages[docCurrentIndex]"
                alt="Loading Image"
                style="width: 650px; height: 350px; padding-left: 70px" />
            </div>
          </div>
        </div>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import { uuid } from "vue-uuid";
import { mapGetters } from "vuex";
import axios from "axios";
import * as echarts from "echarts";
import html2canvas from "html2canvas";
import CourseFileDialog from "@/components/CourseFileDialog";
import DicCatalogTree from "@/components/DicTreeSelect";
import { fetchFile } from "@/api/course/file";
import { getCourseKnowledge } from "@/api/course/course";
import { updateCourseKnowledge, resetGraph } from "@/api/course/course";
import SecondSet from "@/components/SecondSet";
import VideoPlayer from "@/components/VideoPlayer";
import PdfReader from "@/components/PdfReader";
import { saveDataGetId } from "@/api/course/course";
import DigitalHumanGennerate from "@/components/DigitalHumanGenerate";

export default {
  name: "pointList",
  components: {
    SecondSet,
    DicCatalogTree,
    CourseFileDialog,
    PdfReader,
    VideoPlayer,
    DigitalHumanGennerate,
  },
  props: {
    value: {
      type: Array,
      default: () => [],
    },
    isDigitalHuman: {
      type: Boolean,
      default: false,
    },
    isStudent: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      changeNode: null,
      treeData: [],
      defaultProps: {
        children: "children",
        label: "label",
      },
      dialogVisible: false,
      excludes: [],
      jobId: null,
      jobQueryTimer: null,
      positionBeforeYou: 0,
      pointList: [
        {
          id: 1,
          chapter: "第一章：基础概念",
          sub_chapters: [
            {
              id: 11,
              sub_chapter: "1.1 数据结构入门",
              points: [
                { point: "定义", content: "数据结构是组织和存储数据的系统方法" },
                { point: "应用场景", content: "数据库索引设计、操作系统文件管理" },
              ],
            },
          ],
        },
        {
          id: 2,
          chapter: "第二章：线性结构",
          sub_chapters: [
            {
              id: 21,
              sub_chapter: "2.1 数组与链表",
              points: [
                { point: "静态数组", content: "连续内存分配，支持随机访问" },
                { point: "动态数组", content: "自动扩容的数组实现" },
              ],
            },
          ],
        },
      ],
      liveData: {},
      batchVisible: false,
      batchForm: {
        needLearn: 0,
        points: 0,
        faceStart: false,
        faceInterval: 0,
      },
      catDialog: false,
      catId: null,
      importForm: {
        excludes: [],
      },
      previewVisible: false,
      previewData: {},
      extrVisible: false,
      windowHeight:
        window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight,
      postForm: {},
      uploadParams: {},
      iframeBaseUrl: "",
      iframeUrl: "",
      tempId: `temp_${uuid.v4()}`,
      docLoading: false,
      docExtrLoading: false,
      docBtnLoading: false,
      docFlag: false,
      docFileId: null,
      docUploadSuccessReturnId: null,
      docProgress: 0,
      docCurrentIndex: 0,
      docCurrentText: "",
      docProgressText: "",
      timeStamp: Date.now(),
      loadingImages: [
        require("@/assets/gr.png"),
        require("@/assets/loadingpicture/loading2.jpg"),
        require("@/assets/loadingpicture/loading3.jpg"),
        require("@/assets/loadingpicture/loading4.jpg"),
        require("@/assets/loadingpicture/load5.jpg"),
      ],
      extractURI: "http://10.21.22.107:3000",
      // 图谱组件相关
      showGraphComponent: false,
      graphLoading: false,
      chartInstance: null,
      // 等待知识点抽取相关
      tips: [
        "请耐心等待，系统正在为您处理知识点抽取。",
        "您可以在此期间浏览其他课程内容。",
        "知识点抽取和传入内容数量强相关，为了保证生成速度，请尽量降低传入的资料大小",
        "感谢您的耐心，知识点抽取是为了提供更优质的学习体验。",
      ],
      tipIndex: 0,
      tipTimer: null, // 用于存储定时器ID
      progressColor: "#409EFF",
    };
  },
  computed: {
    computedExpand() {
      const arr = [];
      this.pointList.map((item) => {
        if (item.fileList && item.fileList.length > 0) {
          arr.push(item.id);
        }
      });
      return arr;
    },
    ...mapGetters(["zlBaseUrl"]),
    // 等待界面相关计算属性
    estimatedTime() {
      // 根据队列位置估算等待时间
      if (this.positionBeforeYou === 0) {
        return "10-20分钟";
      } else if (this.positionBeforeYou <= 3) {
        return "1-2小时";
      } else if (this.positionBeforeYou <= 10) {
        return "5-8小时";
      } else {
        return "1天以上";
      }
    },
    currentTip() {
      // 获取当前显示的提示
      return this.tips[this.tipIndex];
    },
  },
  watch: {
    value: {
      handler(val) {
        this.pointList = val;
        if (this.pointList && this.pointList.length) {
          this.treeData = JSON.parse(this.pointList[0].desKnowledge);
        }
      },
      deep: true,
    },

    // 检测查询变化
    pointList: {
      handler(val) {
        this.$emit("input", val);
        this.processExcludes();
      },
      deep: true,
    },
    treeData: {
      handler(val) {
        console.log("tcd");
        this.pointList[0].desKnowledge = JSON.stringify(this.treeData);
        console.log(this.pointList);
        this.$emit("updateList", this.pointList);
      },
      deep: true,
    },
  },
  created() {
    this.iframeBaseUrl = `${this.zlBaseUrl}/#/navigation/documentIpt`;
    this.pointList = this.value;
    if (this.pointList.length) {
      this.treeData = JSON.parse(this.pointList[0].desKnowledge);
    }
    /*this.treeData=this.originalData
    console.log(JSON.stringify(this.treeData))*/
  },
  mounted() {
    window.addEventListener("message", (res) => {
      if (res.data && res.data instanceof Object) {
        if (res.data.closeIframe) {
          this.closeExtr();
        }
      }
    });

    this.startTipCarousel();
    // 从URL中获取课程ID
    this.getCourseIdFromUrl();
  },
  beforeDestroy() {
    // 组件销毁前清除定时器
    this.clearTipCarousel();
  },
  methods: {
    // 启动提示轮播
    startTipCarousel() {
      this.clearTipCarousel(); // 先清除可能存在的定时器
      this.tipTimer = setInterval(() => {
        this.nextTip();
      }, 3000); // 每3秒切换一次提示
    },

    // 清除提示轮播定时器
    clearTipCarousel() {
      if (this.tipTimer) {
        clearInterval(this.tipTimer);
        this.tipTimer = null;
      }
    },

    checkJobOnce() {
      try {
        console.log(this.jobId);
        axios
          .post(`${this.extractURI}/check`, {
            job_id: this.jobId,
          })
          .then((res) => {
            console.log(res, "essss");
            if (res.data.status == "finished") {
              clearInterval(this.jobQueryTimer);
              localStorage.clear(this.postForm.id);
              this.jobId = null;
              this.jobQueryTimer = null;
              this.$message.success("当前正在进行的知识点抽出已经结束");
              //请求课程数据
              getCourseKnowledge("1901460476697554946")
                .then(({ data }) => {
                  point = data.point;
                  this.treeData = JSON.parse(point);
                })
                .cache((e) => {
                  console.log(e);
                });
            } else {
              this.positionBeforeYou = res.data.position_before_you;
            }
          })
          .catch((error) => {
            clearInterval(this.jobQueryTimer);
            localStorage.clear(this.postForm.id);
            this.jobId = null;
            this.jobQueryTimer = null;
          });
      } catch {
        clearInterval(this.jobQueryTimer);
        localStorage.clear(this.postForm.id);
        this.jobId = null;
        this.jobQueryTimer = null;
      }
    },
    // 检测任务状态，15s轮询一次
    checkJob() {
      if (this.jobId) {
        this.checkJobOnce();
        this.jobQueryTimer = setInterval(this.checkJobOnce, 1000 * 15);
      } else {
        return false;
      }
      return true;
    },

    // 获取URL中的课程ID
    getCourseIdFromUrl() {
      const url = window.location.href;
      const match = url.match(/\/update\/(\d+)/);
      if (match && match[1]) {
        this.postForm.id = match[1];
        console.log("从URL中获取课程ID：", this.postForm.id);
      }
      this.uploadParams = {
        course_id: this.postForm.id,
        time_stamp: this.timeStamp,
      };
      if (localStorage.getItem(this.postForm.id)) {
        this.jobId = localStorage.getItem(this.postForm.id);
        this.checkJob();
      }
    },
    // 数据转换
    transformData(data) {
      return data.map((chapter, cIndex) => ({
        id: `chapter_${cIndex}`,
        label: chapter.chapter,
        type: "chapter",
        children: chapter.sub_chapters.map((sub, sIndex) => ({
          id: `sub_${cIndex}_${sIndex}`,
          label: sub.sub_chapter,
          type: "sub_chapter",
          children: sub.points.map((point, pIndex) => ({
            id: `point_${cIndex}_${sIndex}_${pIndex}`,
            label: point.point,
            type: "point",
            content: point.content,
            prerequisites: point.prerequisites,
          })),
        })),
      }));
    },

    // 添加 SubChapter
    addSubChapter(node, data) {
      this.$prompt("请输入子章节名称", "添加子章节", {
        inputPlaceholder: "例如：1.2 算法基础",
      }).then(({ value }) => {
        if (!value) return;
        const newSubChapter = {
          sub_chapter: value,
          points: [],
        };
        if (!data.children) {
          this.$set(data, "children", []);
        }
        data.children.push({
          id: `sub_${Date.now()}`,
          label: newSubChapter.sub_chapter,
          type: "sub_chapter",
          children: [],
        });
        updateCourseKnowledge(this.pointList[0].courseId, JSON.stringify(this.treeData))
          .then(() => {
            this.$message.success("添加成功");
            resetGraph(this.pointList[0].courseId);
          })
          .catch(() => {
            this.$message.error("添加失败");
          });
      });
    },

    // 添加 Point
    // 添加 Point
    addPoint(node, data) {
      this.$msgbox({
        title: "添加知识点",
        message: `
      <div>
        <div class="el-form-item">
          <div class="el-form-item__label">知识点标题</div>
          <input id="new-knowledge-label" class="el-input__inner" placeholder="例如：时间复杂度" />
        </div>
        <div class="el-form-item" style="margin-top: 10px;">
          <div class="el-form-item__label">知识点内容</div>
          <textarea id="new-knowledge-content" class="el-textarea__inner" rows="4" placeholder="请输入知识点内容">请输入内容</textarea>
        </div>
      </div>
    `,
        dangerouslyUseHTMLString: true,
        showCancelButton: true,
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        beforeClose: (action, instance, done) => {
          if (action === "confirm") {
            const newLabel = document.getElementById("new-knowledge-label").value;
            const newContent = document.getElementById("new-knowledge-content").value;

            if (!newLabel) {
              this.$message.error("请输入知识点标题");
              return;
            }

            const newPoint = {
              point: newLabel,
              content: newContent || "请输入内容",
              prerequisites: [],
            };

            if (!data.children) {
              this.$set(data, "children", []);
            }

            data.children.push({
              id: `point_${Date.now()}`,
              label: newPoint.point,
              type: "point",
              content: newPoint.content,
              prerequisites: newPoint.prerequisites,
            });

            updateCourseKnowledge(this.pointList[0].courseId, JSON.stringify(this.treeData))
              .then(() => {
                this.$message.success("添加成功");
                resetGraph(this.pointList[0].courseId);
                done();
              })
              .catch(() => {
                this.$message.error("添加失败");
                done();
              });
          } else {
            done();
          }
        },
      });
    },

    // 删除 Point
    deletePoint(node, data) {
      const parent = node.parent;
      const children = parent.data.children || parent.data;
      const index = children.findIndex((d) => d.id === data.id);
      children.splice(index, 1);

      updateCourseKnowledge(this.pointList[0].courseId, JSON.stringify(this.treeData))
        .then(() => {
          this.$message.success("删除成功");
          resetGraph(this.pointList[0].courseId);
        })
        .catch(() => {
          this.$message.error("删除失败");
        });
    },

    // 删除 SubChapter
    deleteSubChapter(node, data) {
      const parent = node.parent;
      const children = parent.data.children || parent.data;
      const index = children.findIndex((d) => d.id === data.id);
      children.splice(index, 1);
      updateCourseKnowledge(this.pointList[0].courseId, JSON.stringify(this.treeData))
        .then(() => {
          this.$message.success("删除成功");
          resetGraph(this.pointList[0].courseId);
        })
        .catch(() => {
          this.$message.error("删除失败");
        });
    },

    // 修改 Point
    editPoint(data) {
      this.changeNode = data;
      let tempLabel = data.label;
      let tempContent = data.content || "";

      this.$msgbox({
        title: "修改知识点",
        message: `
      <div>
        <div class="el-form-item">
          <div class="el-form-item__label">知识点标题</div>
          <input id="knowledge-label" class="el-input__inner" value="${tempLabel}" placeholder="请输入知识点标题" />
        </div>
        <div class="el-form-item" style="margin-top: 10px;">
          <div class="el-form-item__label">知识点内容</div>
          <textarea id="knowledge-content" class="el-textarea__inner" rows="4" placeholder="请输入知识点内容">${tempContent}</textarea>
        </div>
      </div>
    `,
        dangerouslyUseHTMLString: true,
        showCancelButton: true,
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        beforeClose: (action, instance, done) => {
          if (action === "confirm") {
            const newLabel = document.getElementById("knowledge-label").value;
            const newContent = document.getElementById("knowledge-content").value;

            data.label = newLabel;
            data.content = newContent;

            // 更新知识点
            updateCourseKnowledge(this.pointList[0].courseId, JSON.stringify(this.treeData))
              .then(() => {
                this.$message.success("修改成功");
                resetGraph(this.pointList[0].courseId);
                done();
              })
              .catch(() => {
                this.$message.error("修改失败");
                done();
              });
          } else {
            done();
          }
        },
      });
    },
    checkGraph() {
      if (this.pointList.length <= 0) {
        this.$message.error("请先进行知识点抽取");
        return;
      } else {
        // 直接在对话框中展示知识图谱，而不是通过iframe
        this.extrVisible = true;
        this.showGraphComponent = true;
        // 确保在DOM更新后初始化图表
        this.$nextTick(() => {
          // 图表会在组件挂载时自动加载数据和初始化
          this.fetchKnowledgeGraphData(this.postForm.id);
        });
      }
    },

    async showZLUpload() {
      // 切换打开为知识点抽取
      this.showGraphComponent = false;
      console.log("showZLUpload", this.postForm.id);

      if (!this.postForm.id) {
        this.postForm.id = this.tempId;
      }
      this.extrVisible = true;
    },
    closeExtr() {
      this.extrVisible = false;
    },

    // 移除目录
    removeDir(index) {
      this.pointList.splice(index, 1);
    },

    // 移除文件
    removeFile(fileList, index2) {
      fileList.splice(index2, 1);
    },

    createDir() {
      this.$prompt("请输入知识点名称", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
      }).then(({ value }) => {
        for (let i = 0; i < this.pointList.length; i++) {
          if (this.pointList[i].title === value) {
            this.$message.error(`知识点名称：${value}重复了，请换一个！`);
            return;
          }
        }

        this.pointList.push({ title: value, fileList: [] });
      });
    },

    batchAddDir(data) {
      if (data.length > 0) {
        /* const newArr = []
        data.map(oItem => {
          oItem.content.map((item, index) => {
            if (this.pointList.filter(dItem => dItem.title == item.point).length>0) {
              return
            }
            newArr.push({ title: item.point, fileList: [], id: parseInt(Math.random() * 100000) + String((index + 1)) })
          })
        })

        this.pointList = this.pointList.concat(newArr)*/
        this.treeData = this.transformData(data);
      }
    },

    fileDialog(index) {
      console.log("childComponent");

      this.curIndex = index;
      this.dialogVisible = true;
      this.$refs.childComponent.handleAdd();
    },

    dialogSelect(objs) {
      if (objs != null && objs.length > 0) {
        for (let i = 0; i < objs.length; i++) {
          this.pointList[this.curIndex].fileList.push({
            fileId: objs[i].id,
            fileUrl: objs[i].fileUrl,
            title: objs[i].title,
            fileType: objs[i].fileType,
            fileType_dictText: objs[i].fileType_dictText,
            needLearn: objs[i].duration,
            points: 0,
          });
        }
      }

      console.log("objs", objs);
    },

    sortDownDir(dirIndex) {
      const newIndex = dirIndex + 1;
      const targetIndex = this.pointList.splice(dirIndex, 1)[0];
      this.pointList.splice(newIndex, 0, targetIndex);
    },

    sortUpDir(dirIndex) {
      const newIndex = dirIndex - 1;
      const targetIndex = this.pointList.splice(dirIndex, 1)[0];
      this.pointList.splice(newIndex, 0, targetIndex);
    },

    sortDownFile(fileList, fileIndex) {
      const newIndex = fileIndex + 1;
      const targetIndex = fileList.splice(fileIndex, 1)[0];
      fileList.splice(newIndex, 0, targetIndex);
    },

    sortUpFile(fileList, fileIndex) {
      const newIndex = fileIndex - 1;
      const targetIndex = fileList.splice(fileIndex, 1)[0];
      fileList.splice(newIndex, 0, targetIndex);
    },

    // 处理已在列表的文件，避免重复加入
    processExcludes() {
      const ids = [];
      for (let i = 0; i < this.pointList.length; i++) {
        const files = this.pointList[i].fileList;
        if (!files || files.length <= 0) {
          continue;
        }
        for (let j = 0; j < files.length; j++) {
          ids.push(files[j].fileId);
        }
      }

      this.excludes = ids;
    },

    batchDialog() {
      this.batchVisible = true;
    },

    confirmBatch() {
      this.batchVisible = false;

      for (let i = 0; i < this.pointList.length; i++) {
        const fileList = this.pointList[i].fileList;
        if (fileList.length > 0) {
          for (let j = 0; j < fileList.length; j++) {
            if (this.batchForm.needLearnCk) {
              fileList[j].needLearn = this.batchForm.needLearn;
            }

            if (this.batchForm.pointsCk) {
              fileList[j].points = this.batchForm.points;
            }
          }
        }
      }

      this.$forceUpdate();
    },

    importCat() {
      this.catDialog = true;
    },

    handleImport() {
      // 根据分类找到结构
      this.catDialog = false;

      // 批量添加目录
      this.importForm.excludes = this.excludes;

      fetchFile(this.importForm).then((res) => {
        for (let i = 0; i < res.data.length; i++) {
          const dir = res.data[i];
          this.pointList.push(dir);
        }
      });
    },

    handlePreview(data) {
      console.log("pv", data);
      this.previewVisible = true;
      this.previewData.fileType = data.fileType;
      this.previewData.viewUrl = data.viewUrl || data.fileUrl;
      this.previewData.fileUrl = data.fileUrl;
    },

    closePreview() {
      this.previewData = {};
    },

    vieoLoadError(e) {
      this.previewVisible = false;
      this.$message({
        type: "error",
        message: "授课视频正在生成中，暂不能预览",
        duration: 3000,
      });
    },
    handleDocExceed(files) {
      this.docBtnLoading = false;
      this.$refs.docUpload.clearFiles();
      const file = files[0];
      this.$refs.docUpload.handleStart(file);
    },
    handleDocRemove() {
      // 清除文件数据
    },
    handleDocBeforeUpload(file) {
      const isLt2M = file.size / 1024 / 1024 < 100;
      if (!isLt2M) {
        this.$message.error("上传的文件大小不能超过 100MB!");
      }
      return isLt2M;
    },
    handleDocSuccess(response, file, fileList) {
      this.docFlag = true;
      this.docFileId = response.file_id;
      this.docBtnLoading = false;
      this.$message({
        message: "文件上传成功！",
        type: "success",
        duration: 2000,
      });
      this.docUploadSuccessReturnId = response.id;
    },
    handleDocError(err, file, fileList) {
      this.docBtnLoading = false;
      this.$message({
        message: "文件上传失败！",
        type: "error",
        duration: 2000,
      });
    },
    handleDocFileChange() {
      // 文件变更时的处理
    },
    submittextStructure() {
      if (this.docFlag && this.docUploadSuccessReturnId) {
        this.docExtrLoading = true;
        const formData = new FormData();
        formData.append("id", this.docUploadSuccessReturnId);
        formData.append("course_id", this.postForm.id);
        formData.append("time_stamp", this.timeStamp);

        axios
          .post(`${this.extractURI}/extract`, formData, {
            timeout: 30 * 60 * 1000,
          })
          .then((res) => {
            this.docExtrLoading = false;
            if (res.status == 202) {
              localStorage.setItem("chap", JSON.stringify(res.data));
              localStorage.setItem(this.postForm.id, res.data.job_id);
              this.jobId = res.data.job_id;
              this.checkJob();
              this.$message({
                message: "知识点开始抽取",
                type: "success",
                duration: 2000,
              });
              this.$store.commit("SET_CHAP", JSON.stringify(res.data));
              if (res.data && res.data.length > 0) {
                this.batchAddDir(res.data);
              }
              this.docFlag = false;
              this.$refs.docUpload.clearFiles();
              this.closeExtr();
            } else {
              this.docExtrLoading = false;
              this.$message.error(`${res.status}接口响应错误`);
            }
          })
          .catch((error) => {
            this.docExtrLoading = false;
            this.$message.error("知识点生成失败！");
          });
        return;
      } else {
        this.$message.error("请先上传文件");
      }
    },

    // 获取后端知识图谱的数据
    async fetchKnowledgeGraphData(courseId) {
      this.graphLoading = true;
      try {
        const response = await axios.post(
          `http://111.63.183.17:5000/Graphdata?course_id=${courseId}`,
          {}
        );
        // 处理节点id为字符串类型
        const processedData = this.processGraphData(this.processNodeIds(response.data));
        this.$nextTick(() => {
          this.initChart(processedData);
          this.graphLoading = false;
        });
      } catch (error) {
        console.error("数据获取失败:", error);
        this.$message.error("获取知识图谱数据失败");
        this.graphLoading = false;
      }
    },

    // 重新生成知识图谱
    async regenerateGraph() {
      this.graphLoading = true;
      try {
        const response = await axios.post(
          `http://111.63.183.17:5000/ResetGraph?course_id=${this.postForm.id}`,
          {}
        );
        // 处理节点id为字符串类型
        const processedData = this.processGraphData(this.processNodeIds(response.data));
        this.$nextTick(() => {
          this.initChart(processedData);
          this.graphLoading = false;
        });
      } catch (error) {
        console.error("数据获取失败:", error);
        this.$message.error("重新生成知识图谱失败");
        this.graphLoading = false;
      }
    },

    // 处理节点id为字符串类型
    processNodeIds(data) {
      data.nodes.forEach((node) => {
        node.id = String(node.id); // 将id转换为字符串类型
      });
      data.links.forEach((link) => {
        link.source = String(link.source); // 将id转换为字符串类型
        link.target = String(link.target); // 将id转换为字符串类型
      });
      return data;
    },

    // 处理原始数据代码
    processGraphData(data) {
      const nodes = [];
      const links = [];
      console.log(data);
      const nodeMap = new Map();
      // 节点处理
      data.nodes.forEach((node) => {
        const processedNode = {
          id: String(node.id),
          name: node.name,
          description: node.description,
          level: 0,
          children: [],
          isCollapsed: false,
          symbolSize: 30,
          itemStyle: { color: "#5470c6" },
        };
        nodes.push(processedNode);
        nodeMap.set(String(node.id), processedNode);
      });

      // 通过Map精确获取节点引用
      data.links.forEach((link) => {
        // 强制转换source/target为字符串类型
        const sourceId = String(link.source);
        const targetId = String(link.target);

        // 从Map中获取实际节点对象（而非临时变量）
        const sourceNode = nodeMap.get(sourceId);
        const targetNode = nodeMap.get(targetId);

        if (sourceNode && targetNode) {
          sourceNode.children.push(targetNode); // 直接操作Map中的引用
          this.updateNodeLevels(targetNode, sourceNode.level + 1); // 处理层级
          links.push({ source: sourceId, target: targetId });
        } else {
          console.warn(`Invalid link: source=${sourceId}或target=${targetId}未找到`);
        }
      });

      // 根据层级设置不同颜色
      const colorMap = ["#5470c6", "#91cc75", "#f1c232", "#ff7f0e", "#d62728"]; // 你可以根据需要调整颜色

      nodes.forEach((node) => {
        node.symbolSize = 30 - node.level * 5; // 随着层级增加，节点变小
        node.itemStyle.color = colorMap[node.level] || "#b0b0b0"; // 设置不同层级的颜色，如果超出指定层级则使用默认颜色
      });

      return { nodes, links };
    },

    // 工具函数，用于 processGraphData 中的节点level更新
    updateNodeLevels(node, level) {
      if (node.level > level) return;
      node.level = level;
      if (node.children) {
        node.children.forEach((child) => {
          this.updateNodeLevels(child, level + 1);
        });
      }
    },

    // 初始化图表
    initChart(graphData) {
      console.log("chart", graphData.nodes);
      if (!this.$refs.chartContainer) return;
      this.chartInstance = echarts.init(this.$refs.chartContainer);

      const option = {
        tooltip: {
          formatter: (params) => {
            if (params.dataType === "node") {
              return `${params.data.name}<br/>${params.data.description || "暂无详细描述"}`;
            }
          },
        },
        series: [
          {
            type: "graph",
            layout: "force",
            data: graphData.nodes,
            links: graphData.links,
            roam: true, // 支持图表拖动
            focusNodeAdjacency: true, // 鼠标悬停时高亮邻居节点
            label: {
              show: true,
              position: "right",
              formatter: "{b}", // 显示节点名称
            },
            force: {
              repulsion: 100,
              gravity: 0.1,
              edgeLength: 50,
            },
            emphasis: {
              focus: "adjacency",
              label: {
                show: true,
              },
            },
            // 设置链接的样式
            lineStyle: {
              color: "#ccc",
              width: 3,
            },
            draggable: true, // 开启节点拖拽功能
          },
        ],
      };

      this.chartInstance.setOption(option);

      // 窗口自适应
      window.addEventListener("resize", () => this.chartInstance && this.chartInstance.resize());

      // 事件监听：点击节点折叠子节点
      this.chartInstance.on("click", (event) => {
        if (event.dataType === "node") {
          const clickedNodeId = event.data.id;
          this.toggleCollapse(clickedNodeId, graphData);
        }
      });
    },

    // 折叠/展开节点（仅折叠子节点）
    toggleCollapse(nodeId, graphData) {
      const node = graphData.nodes.find((n) => n.id === nodeId);

      if (node) {
        node.isCollapsed = !node.isCollapsed;

        // 更新节点及其连接关系
        if (node.isCollapsed) {
          // 折叠时，隐藏该节点的所有子节点，并删除与子节点的连接
          this.collapseNodeChildren(node, graphData);
        } else {
          // 展开时，恢复该节点的所有子节点，并恢复连接
          this.expandNodeChildren(node, graphData);
        }

        // 更新图谱数据
        this.updateGraphData(graphData);
      }
    },

    // 折叠节点的子节点及其连接
    collapseNodeChildren(node, graphData) {
      if (!node.children || node.children.length === 0) return;

      // 递归折叠每个子节点
      for (let i = 0; i < node.children.length; i++) {
        const child = node.children[i];
        // 删除子节点
        graphData.nodes = graphData.nodes.filter((n) => n.id !== child.id);
        // 删除与子节点的链接
        graphData.links = graphData.links.filter(
          (link) => link.source !== child.id && link.target !== child.id
        );
        this.collapseNodeChildren(child, graphData); // 递归折叠子节点
      }
    },

    // 展开节点的子节点及其连接
    expandNodeChildren(node, graphData) {
      // 恢复该节点
      if (!graphData.nodes.find((n) => n.id === node.id)) {
        graphData.nodes.push(node);
      }

      // 恢复该节点的子节点及其连接
      if (node.children && node.children.length > 0) {
        for (let i = 0; i < node.children.length; i++) {
          const child = node.children[i];
          // 恢复父子节点的连接
          if (
            !graphData.links.some((link) => link.source === node.id && link.target === child.id)
          ) {
            graphData.links.push({ source: node.id, target: child.id });
          }

          // 递归展开子节点
          this.expandNodeChildren(child, graphData);
        }
      }
    },

    // 更新图谱数据
    updateGraphData(graphData) {
      const updatedNodes = [];
      const updatedLinks = [];

      // 更新节点和链接
      graphData.nodes.forEach((node) => {
        if (!node.isCollapsed) {
          updatedNodes.push(node);
        }

        // 处理子节点的链接
        if (Array.isArray(node.children)) {
          for (let i = 0; i < node.children.length; i++) {
            const child = node.children[i];
            if (!child.isCollapsed) {
              updatedLinks.push({
                source: node.id,
                target: child.id,
              });
            } else {
              // 保留折叠节点和父节点的链接
              updatedLinks.push({
                source: node.id,
                target: child.id,
              });
            }
          }
        }
      });
      // 在更新图表时，保留折叠的节点
      graphData.nodes.forEach((node) => {
        if (node.isCollapsed && !updatedNodes.find((n) => n.id === node.id)) {
          updatedNodes.push(node); // 将折叠的节点加入
        }
      });

      // 更新图表
      this.chartInstance.setOption({
        series: [
          {
            data: updatedNodes,
            links: updatedLinks,
          },
        ],
      });
    },

    // 全屏显示图谱
    fullScreen() {
      const container = this.$refs.chart_container;
      if (container) {
        if (container.requestFullscreen) {
          container.requestFullscreen();
        } else if (container.webkitRequestFullscreen) {
          // 兼容 WebKit 浏览器
          container.webkitRequestFullscreen();
        } else if (container.mozRequestFullScreen) {
          // 兼容 Firefox
          container.mozRequestFullScreen();
        }
      }
    },

    // 下载图谱图片
    async downloadImage() {
      try {
        const canvas = await html2canvas(this.$refs.chart_container);
        const image = canvas.toDataURL("image/png");
        const link = document.createElement("a");
        link.href = image;
        link.download = "knowledge_graph.png";
        link.click();
      } catch (error) {
        console.error("下载图谱失败:", error);
        this.$message.error("下载图谱失败");
      }
    },

    // 等待界面相关方法
    prevTip() {
      this.tipIndex = (this.tipIndex - 1 + this.tips.length) % this.tips.length;
      this.startTipCarousel(); // 重置定时器
    },

    nextTip() {
      this.tipIndex = (this.tipIndex + 1) % this.tips.length;
      this.startTipCarousel(); // 重置定时器
    },

    // 刷新队列状态
    checkQueuePosition() {
      if (!this.jobId) return;

      this.$message({
        type: "info",
        message: "正在刷新队列状态...",
        duration: 1500,
      });

      axios
        .post(`${this.extractURI}/check`, {
          job_id: this.jobId,
        })
        .then((res) => {
          if (res.data && res.data.position_before_you !== undefined) {
            this.positionBeforeYou = res.data.position_before_you;

            if (res.data.status === "finished") {
              clearInterval(this.jobQueryTimer);
              localStorage.clear(this.postForm.id);
              this.jobId = null;
              this.jobQueryTimer = null;
              this.$message.success("知识点抽取已完成");
              //TODO：重新生成知识图谱，刷新知识点列表
            } else {
              this.$message.success("队列状态已更新");
            }
          }
        })
        .catch((error) => {
          console.error("刷新队列状态失败:", error);
          this.$message.error("刷新队列状态失败");
        });
    },

    // 取消知识点抽取
  },
};
</script>

<style scoped lang="scss">
.knowledge-tree {
  ::v-deep .el-tree-node {
    margin: 12px 0;
    position: relative; // 确保层级独立
    z-index: 1; // 防止下方行覆盖上方行

    // 调整每一行的行高
    .el-tree-node__content {
      height: auto; // 设置行高
      display: flex;
      align-items: center;
    }

    // 章节样式（一级标题）

    .chapter {
      /*background-color: #f0f8ff; // 淡蓝色背景*/
      border-radius: 8px;
      font-size: 18px;
      font-weight: 800;
      color: darkblue;
    }

    // 子章节样式（二级标题）
    .sub_chapter {
      font-size: 16px;
      font-weight: 800;
      color: #34495e;
    }

    // 知识点样式（三级标题）
    .point {
      font-size: 14px;
      font-weight: 400;
      color: #7f8c8d;

      .content-text {
        font-size: 13px;
        color: #95a5a6;
      }
    }

    // 先决条件标签样式
    .prerequisites {
      margin-left: 10px;

      .el-tag {
        margin-right: 5px;
        transform: scale(0.9);
      }
    }
  }

  .tree-node {
    display: flex;
    align-items: center;
    width: 100%;
    height: 40px;

    .content-text {
      margin-left: 10px;
      font-size: 13px;
      color: #666;
      max-width: 60vw;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }

    .prerequisites {
      margin-left: 10px;

      .el-tag {
        margin-right: 5px;
        transform: scale(0.9);
      }
    }

    .action-buttons {
      margin-left: auto;

      .el-button {
        margin-left: 5px;
      }
    }
  }
}

/deep/.el-button--success {
  background-color: #6f5af6 !important;
  border-color: #6f5af6 !important;
  position: relative;
}

/deep/.el-button--success:active {
  background-color: #501fe3 !important;
  border-color: #501fe3 !important;
}

.handleBtnCont {
  padding-bottom: 20px;

  /deep/.el-button--success::before {
    content: "";
    width: 60px;
    height: 18px;
    background: url("../../../../assets/exam/corner_mark.png") no-repeat;
    background-size: 100% 100%;
    position: absolute;
    top: -50%;
    right: -50%;
  }
}

.document-ipt-wrapper {
  .left {
    width: 100%;
    margin: 0 auto;
    padding: 20px;

    .upload {
      height: 500px;
      margin: 20px auto;
      display: flex;
      align-items: center;
      justify-content: center;
      flex-direction: column;
    }
  }

  /* 知识图谱相关样式 */
  .content_container {
    background-color: white;
    width: 100%;
    height: 80vh;
    border-radius: 10px;
    display: flex;
    justify-content: center;
    align-items: center;

    .tree-chart {
      height: 100%;
      width: 100%;
    }
  }

  .buttons-container {
    margin-top: 20px;
    display: flex;
    justify-content: center;

    .documentIpt_btn {
      width: 120px;
      height: 50px;
      // background-color: #b49c73;
      // border-color: #b49c73;
      color: white;
      font-size: 16px;
      font-weight: 700;
      margin: 0 20px;
    }

    .left_btn,
    .right_btn {
      margin: 0 20px;
    }
  }
}

.loadingall {
  display: flex;

  .loadingleft {
    flex: 0 0 40%;
  }

  .loadingright {
    flex: 0 0 60%;
    display: flex;
    justify-content: center;
    align-items: flex-start;
  }
}

.progress-container {
  margin-left: 80px;
  width: 60%;
  height: 20px;
  background-color: #f5f5f5;
  border-radius: 5px;
}

.progress-bar {
  height: 100%;
  background-color: #007bff;
  transition: width 0.5s ease;
}

.progress-text {
  color: white;
  margin-left: 10px;
}

/* 等待知识点抽取相关样式 */
.waiting-container {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  width: 100%;
  padding: 20px;
  box-sizing: border-box;
}

.waiting-content {
  padding: 20px;
  width: 100%;
}

.waiting-header {
  display: flex;
  align-items: center;
  margin-bottom: 20px;

  i {
    font-size: 24px;
    color: #409eff;
    margin-right: 10px;
  }

  h2 {
    font-size: 18px;
    font-weight: 600;
    color: #333;
    margin: 0;
  }
}

.waiting-position {
  margin-bottom: 20px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: start;

  .progress-wrapper {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 10px;
  }

  .position-info {
    display: flex;
    align-items: center;
    width: 100%;

    .position-number {
      font-size: 22px;
      font-weight: 700;
      color: #409eff;
      margin-right: 5px;
    }

    .position-text {
      font-size: 14px;
      color: #666;
    }
  }
}

.waiting-time {
  font-size: 14px;
  color: #999;
  text-align: center;
  margin-bottom: 20px;
}

.waiting-tips {
  margin-bottom: 20px;
  background-color: #fff;
  border-radius: 8px;
  padding: 15px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);

  h3 {
    font-size: 16px;
    font-weight: 500;
    color: #333;
    margin-bottom: 10px;
  }

  .tip-content {
    width: 100%;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;

    p {
      font-size: 14px;
      color: #666;
      margin: 0 0 10px 0;
      text-align: center;
    }

    .tip-controls {
      display: flex;
      align-items: center;
      justify-content: space-between;

      .tip-nav {
        cursor: pointer;
        font-size: 18px;
        color: #409eff;

        &:hover {
          color: #66b1ff;
        }
      }

      .tip-indicator {
        font-size: 14px;
        color: #999;
      }
    }
  }
}

.waiting-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;

  el-button {
    width: 48%;
  }
}
</style>
